/****************************************************************************
**
** This file is part of qPhotoTag, a photo keywording application
**
** Copyright (C) 2009 Marcell Lengyel <miketkf@gmail.com>
**
** GNU General Public License
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**
****************************************************************************/

/*! \file photoview.cpp
    \brief Contains the implementation of the PhotoView class

    The PhotoView class is used for displaying the photo thumbnails in a
    grid view.
 */
#include <QtGui>
#include "photoview.h"
#include "picturepreviewdialog.h"

PhotoView::PhotoView(QWidget *parent)
	: QListView(parent)
{
	QSize iconGridSize;
	QSize iconSize;
        iconGridSize.setHeight(ICON_GRID_HEIGHT);
        iconGridSize.setWidth(ICON_GRID_WIDTH);
        iconSize.setHeight(ICON_HEIGHT);
        iconSize.setWidth(ICON_WIDTH);

        model = new QStandardItemModel(this);
	this->setModel(model);
	this->setViewMode(QListView::IconMode);
	this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	this->setSelectionMode(QAbstractItemView::ExtendedSelection);
	this->setMovement(QListView::Static);
	this->setResizeMode(QListView::Adjust);
	this->setGridSize(iconGridSize);
	this->setIconSize(iconSize);
	this->setUniformItemSizes(false);
	this->setEditTriggers(QListView::NoEditTriggers);
	
	globe = new QPixmap(":/icons/globe.png");
}

PhotoView::~PhotoView()
{
    for (int i = 0; i < photo_list.size(); ++i)
        delete photo_list.at(i);
    delete globe;
}

void PhotoView::keyPressEvent(QKeyEvent *event)
{
    if ((event->key() == Qt::Key_Delete) || (event->key() == Qt::Key_Backspace))
    {
        remove_selected_items();
        emit photoViewDeletePressed();
        event->accept();
    }
    else {
        QListView::keyPressEvent(event);
        event->ignore();
    }
}

void PhotoView::remove_selected_items()
{
    if (is_selection())
    {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::question(this, tr("Remove Pictures"),
                                     tr("Do you really want to remove the selected photos?"),
                                     QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        if (reply == QMessageBox::Yes)
        {
            if (this->selectionModel()->selectedIndexes().size() == photo_list.size())
            {
                // all photos selected
                model->clear();
                photo_list.clear();
            }
            else
            {
                QModelIndex index;
                foreach(index, this->selectionModel()->selectedIndexes())
                {
                    int row = index.row();
                    photo_list.removeAt(row);
                    model->removeRow(row);
                }
            }
        }
    }
}

bool PhotoView::is_selection()
{
	bool retval = false;
	if (! this->selectionModel()->selectedIndexes().empty())
		retval = true;
	return retval;
}

QString PhotoView::strippedName(const QString &fullFileName)
{
	return QFileInfo(fullFileName).fileName();
}

void PhotoView::new_file(const QString &full_path)
{
	QIcon *icon;
	QStandardItem *item;
	Photo *ph = new Photo(full_path);
	photo_list.append(ph);
	if (ph->has_thumbnail())
	{
		QPixmap *thumbnail_pixmap = new QPixmap();
		std::string tn = ph->get_thumbnail();
		uint size = tn.size();
		thumbnail_pixmap->loadFromData(reinterpret_cast<const uchar*>(tn.data()),size);
		if (ph->has_georeference())
		{
			QPainter *painter = new QPainter(thumbnail_pixmap);
			painter->drawPixmap(QPoint(0,0), *globe);
			painter->end();
                        delete painter;
		}
		icon = new QIcon(*thumbnail_pixmap);
                delete thumbnail_pixmap;
		
	}
	else
	{
		icon = new QIcon(full_path);
	}
	item = new QStandardItem(*icon, strippedName(full_path));
	this->model->appendRow(item);
        delete icon;
}

QStringList PhotoView::get_tag_list(){
	QStringList keywords;
	for (int i = 0; i < photo_list.size(); ++i)
	{
		QStringList kws = photo_list.at(i)->get_keywords();
		for (int j = 0; j < kws.size(); ++j)
		{
			if (! keywords.contains(kws.at(j)))
				keywords.append(kws.at(j));
		}
	}
	keywords.sort();
	return keywords;
}

QStringList PhotoView::get_selected_tag_list()
{
    QStringList keywords;
    if (is_selection())
    {
        QModelIndex index;
        bool first_run = true;
        QStringList kws;
        foreach(index, this->selectionModel()->selectedIndexes())
        {
            int row = index.row();
            kws = photo_list.at(row)->get_keywords();
            if (first_run)
            {
                for (int j = 0; j < kws.size(); ++j)
                    keywords.append(kws.at(j));
                first_run = false;
            }
            else
            {
                for (int j = keywords.size() - 1; j >= 0; j--)
                    if (! kws.contains(keywords.at(j)))
                        keywords.removeAt(j);
            }
        }
    }
    keywords.sort();
    return keywords;
}

QString PhotoView::get_selected_caption()
{
	QString caption;
	if (is_selection())
	{
		QModelIndex index;
		bool first_run = true;
		foreach(index, this->selectionModel()->selectedIndexes())
		{
			int row = index.row();
			if (first_run)
			{
				caption = photo_list.at(row)->get_caption();
				first_run = false;
			}
			else
			{
				QString new_caption = photo_list.at(row)->get_caption();
				if (caption.compare(new_caption) 
                                        && ( ! caption.isEmpty()
                                        || ! new_caption.isEmpty()))
					caption = QString("[Multiple values]");
			}
		}
	}
	return caption;
}

bool PhotoView::isEmpty()
{
	return photo_list.isEmpty();
}

void PhotoView::add_tag_to_selected(const QString &new_tag)
{
	if (is_selection() && ! new_tag.isEmpty())
	{
		QStringList kw_list;
		kw_list << new_tag;
		QModelIndex index;
		foreach(index, this->selectionModel()->selectedIndexes())
		{
			int row = index.row();
			photo_list.at(row)->set_keywords(QStringList(),kw_list);
		}
	}
}

void PhotoView::add_tags_to_selected(const QStringList &new_tag_list)
{
	if (is_selection() && ! new_tag_list.isEmpty())
	{
		QStringList kw_list(new_tag_list);
		QModelIndex index;
		foreach(index, this->selectionModel()->selectedIndexes())
		{
			int row = index.row();
			photo_list.at(row)->set_keywords(QStringList(),kw_list);
		}
	}
}

void PhotoView::remove_tags_from_selected(const QStringList &old_tag_list)
{
	if (is_selection() && ! old_tag_list.isEmpty())
	{
		QStringList kw_list(old_tag_list);
		QModelIndex index;
		foreach(index, this->selectionModel()->selectedIndexes())
		{
			int row = index.row();
			photo_list.at(row)->set_keywords(kw_list, QStringList());
		}
	}
}

void PhotoView::add_caption_to_selected(const QString &new_caption)
{
    if (! is_selection())
        return;
    QModelIndex index;
    foreach(index, this->selectionModel()->selectedIndexes())
    {
        int row = index.row();
        photo_list.at(row)->set_caption(new_caption);
    }
}

void PhotoView::save_exif_data()
{
    for (int i = 0; i < photo_list.size(); ++i)
        photo_list.at(i)->save_all();
}

void PhotoView::display_picture_dialog(const QModelIndex &index)
{
    int row = index.row();
    PicturePreviewDialog *dlg = new PicturePreviewDialog(this, photo_list.at(row)->get_fullpath());
    dlg->show();
}

void PhotoView::update_gps_coordinates_to_selected(const double lat, const double lon, const double alt)
{
    if (! is_selection())
        return;
    // loop through all selected photos
    foreach(QModelIndex index, this->selectionModel()->selectedIndexes())
    {
        int row = index.row();
        QStringList old_geo_keywords;
        // loop through the keywords for the current photo
        QStringList kws = photo_list.at(row)->get_keywords();
        for (int j = 0; j < kws.size(); ++j)
        {
                if (kws.at(j).startsWith("geo:l"))
                        old_geo_keywords.append(kws.at(j));
        }
        // new geo: keywords to set
        QStringList new_geo_keywords;
        new_geo_keywords.append(QString("geotagged"));
        new_geo_keywords.append(QString("geo:lat=%1").arg(lat));
        new_geo_keywords.append(QString("geo:lon=%1").arg(lon));
        // remove the old IPTC keywords and set the new ones
        photo_list.at(row)->set_keywords(old_geo_keywords,new_geo_keywords);
        // set EXIF GPS data too
        photo_list.at(row)->setGPSInfo(alt,lat,lon);
        // add the globe icon to the picture thumbnail to show that the photo has
        // georeference
        add_globe(row);
    }


}

void PhotoView::add_globe(int row)
{
    if (model->rowCount() >= row)
    {
        QIcon icon = model->item(row)->icon();
        QPixmap pixmap = icon.pixmap(QSize(ICON_WIDTH,ICON_HEIGHT));
        QPainter *painter = new QPainter(&pixmap);
        painter->drawPixmap(QPoint(0,0), *globe);
        painter->end();
        delete painter;
        icon = QIcon(pixmap);
        model->item(row)->setIcon(icon);
    }
}

void PhotoView::get_lens_data_for_selected(QString &model, Qt::CheckState &model_update,
                                    double &max_aperture, Qt::CheckState &max_aperture_update,
                                    double &fnumber, Qt::CheckState &fnumber_update,
                                    double &focallength, Qt::CheckState &focallength_update)
{
    if (! is_selection())
        return;
    // loop through all selected photos
    bool first = true;
    LENS_DATA lens_data;
    foreach(QModelIndex index, this->selectionModel()->selectedIndexes())
    {
        int row = index.row();
        if (first) {
            first = false;
            photo_list.at(row)->get_lens_data(lens_data);
            model = lens_data.lens_model;
            model_update = (lens_data.lens_model_update == true ? Qt::Checked : Qt::Unchecked) ;
            max_aperture = lens_data.max_aperture;
            max_aperture_update = (lens_data.max_aperture_update == true ? Qt::Checked : Qt::Unchecked) ;
            fnumber = lens_data.fnumber;
            fnumber_update = (lens_data.fnumber_update == true ? Qt::Checked : Qt::Unchecked) ;
            focallength = lens_data.focallength;
            focallength_update = (lens_data.focallength_update == true ? Qt::Checked : Qt::Unchecked) ;
        } else {
            photo_list.at(row)->get_lens_data(lens_data);
            if (model != lens_data.lens_model) {
                model.clear();
                if (model_update == Qt::Checked)
                    model_update = Qt::PartiallyChecked;
            }
            if (model_update != (lens_data.lens_model_update == true ? Qt::Checked : Qt::Unchecked))
                model_update = Qt::PartiallyChecked;
            if (max_aperture != lens_data.max_aperture) {
                max_aperture = 0.0;
                if (max_aperture_update == Qt::Checked)
                    max_aperture_update = Qt::PartiallyChecked;
            }
            if (max_aperture_update != (lens_data.max_aperture_update == true ? Qt::Checked : Qt::Unchecked))
                max_aperture_update = Qt::PartiallyChecked;
            if (fnumber != lens_data.fnumber) {
                fnumber = 0.0;
                if (fnumber_update == Qt::Checked)
                    fnumber_update = Qt::PartiallyChecked;
            }
            if (fnumber_update != (lens_data.fnumber_update == true ? Qt::Checked : Qt::Unchecked))
                fnumber_update = Qt::PartiallyChecked;
            if (focallength != lens_data.focallength) {
                focallength = 0;
                if (focallength_update == Qt::Checked)
                    focallength_update = Qt::PartiallyChecked;
            }
            if (focallength_update != (lens_data.focallength_update == true ? Qt::Checked : Qt::Unchecked))
                focallength_update = Qt::PartiallyChecked;
        }
    }
}

void PhotoView::set_lens_data_for_selected(QString model, Qt::CheckState model_update,
                                    double max_aperture, Qt::CheckState max_aperture_update,
                                    double fnumber, Qt::CheckState fnumber_update,
                                    double focallength, Qt::CheckState focallength_update)
{
    if (! is_selection())
        return;
    // loop through all selected photos
    LENS_DATA lens_data;
    foreach(QModelIndex index, this->selectionModel()->selectedIndexes())
    {
        int row = index.row();
        // get the original data
        photo_list.at(row)->get_lens_data(lens_data);
        // if the checkbox is set or unset, then it goes through
        if (model_update != Qt::PartiallyChecked)
            lens_data.lens_model_update = (model_update == Qt::Checked ? true : false);
        // modify if the checkbox is set
        if (model_update == Qt::Checked)
            lens_data.lens_model = model;
        // if the checkbox is set or unset, then it goes through
        if (max_aperture_update != Qt::PartiallyChecked)
            lens_data.max_aperture_update = (max_aperture_update == Qt::Checked ? true : false);
        // modify if the checkbox is set
        if (max_aperture_update == Qt::Checked)
            lens_data.max_aperture = max_aperture;
        // if the checkbox is set or unset, then it goes through
        if (fnumber_update != Qt::PartiallyChecked)
            lens_data.fnumber_update = (fnumber_update == Qt::Checked ? true : false);
        // modify if the checkbox is set
        if (fnumber_update == Qt::Checked)
            lens_data.fnumber = fnumber;
        // if the checkbox is set or unset, then it goes through
        if (focallength_update != Qt::PartiallyChecked)
            lens_data.focallength_update = (focallength_update == Qt::Checked ? true : false);
        // modify if the checkbox is set
        if (focallength_update == Qt::Checked)
            lens_data.focallength = focallength;
        photo_list.at(row)->set_lens_data(lens_data);

    }
}
